import { FileService } from "@app/file";
import { PrismaService } from "@app/prisma";
import { Args, Int, Mutation, Query, Resolver } from "@nestjs/graphql";
import { CREATE_POWER, DELETE_POWER, GqlAuthGuard, GqlCurrentUser, MakeGqlAuthPowerGuard, NoAuthGqlAuthGuard, UPDATE_POWER, VIEW_POWER } from "src/auth/auth.guard";
import { TestService } from "./test.service";
import { SysTestGroupEntity } from "@app/prisma/sys.test.group.entity/sys.test.group.entity";
import { UseGuards } from "@nestjs/common";
import { ForbiddenError } from "@nestjs/apollo";
import { SysTestEntity } from "@app/prisma/sys.test.entity/sys.test.entity";
import { SysTestChapterEntity } from "@app/prisma/sys.test.chapter.entity/sys.test.chapter.entity";
import { SysTestPaperEntity } from "@app/prisma/sys.test.paper.entity/sys.test.paper.entity";
import { number } from "joi";
import { SysUserEntity } from "@app/prisma/sys.user.entity/sys.user.entity";
import { QuestionService } from "src/question/question.service";

export const TestGuard = MakeGqlAuthPowerGuard("/test", "模拟测试")
@Resolver()
export class TestResolver {
  constructor(
    private readonly prisma: PrismaService,
    private readonly file: FileService,
    private readonly service: TestService,
    private readonly questionService: QuestionService
  ) { }

  //模拟测试组
  @Query(() => [SysTestGroupEntity])
  queryTestGroups() {
    return this.prisma.sys_test_group.findMany()
  }

  @Query(() => SysTestGroupEntity)
  queryTestGroupById(
    @Args("id", { type: () => Int }) id: number,
  ) {
    return this.prisma.sys_test_group.findUnique({
      where: {
        id
      }
    })
  }

  @Mutation(() => SysTestGroupEntity)
  @UseGuards(TestGuard([CREATE_POWER]))
  async createTestGroup(
    @Args("name") name: string,
    @Args("base64") base64: string,
    @Args("desc", { nullable: true }) desc?: string,
    @Args("order", { nullable: true, type: () => Int }) order?: number,
    @Args("status", { nullable: true }) status?: boolean,
  ) {
    return await this.service.createTestGroup(name, base64, desc, order, status)
  }
  @Mutation(() => SysTestGroupEntity)
  @UseGuards(TestGuard([UPDATE_POWER]))
  async updateTestGroup(
    @Args("id", { type: () => Int }) id: number,
    @Args("name") name: string,
    @Args("base64", { nullable: true }) base64?: string,
    @Args("desc", { nullable: true }) desc?: string,
    @Args("order", { nullable: true, type: () => Int }) order?: number,
    @Args("status", { nullable: true }) status?: boolean,
  ) {
    const entity = await this.prisma.sys_test_group.update({
      where: {
        id
      },
      data: {
        name,
        desc,
        order,
        status
      }
    })
    if (!entity) throw new ForbiddenError("404")
    if (!!base64) {
      const buffer = this.file.base64_to_buffer(base64)
      this.file.writeFile(this.service.getGroupAvatarPath(entity), buffer);
    }
    return entity
  }
  @Mutation(() => SysTestGroupEntity)
  @UseGuards(TestGuard([DELETE_POWER]))
  async deleteTestGroup(
    @Args("id", { type: () => Int }) id: number,
  ) {
    const entity = await this.prisma.sys_test_group.delete({
      where: {
        id
      }
    })
    if (!entity) throw new ForbiddenError("404")
    return entity
  }


  //模拟测试
  @Query(() => [SysTestEntity])
  queryTests(
    @Args("id", { type: () => Int }) id: number,
  ) {
    return this.prisma.sys_test.findMany({
      where: {
        sys_test_groupId: id
      }
    })
  }

  @Query(() => SysTestEntity)
  queryTestById(
    @Args("id", { type: () => Int }) id: number,
  ) {
    return this.prisma.sys_test.findUnique({
      where: {
        id
      }
    })
  }

  @Query(() => [SysTestEntity])
  async queryRecentModifiedTest(
    @Args("size", { type: () => Int, nullable: true }) size?: number,
  ) {
    return await this.prisma.sys_test.findMany({
      orderBy: [
        {
          updateAt: "desc"
        }
      ],
      take: size
    })
  }

  @Mutation(() => SysTestEntity)
  @UseGuards(TestGuard([CREATE_POWER]))
  async createTest(
    @Args("name") name: string,
    @Args("base64") base64: string,
    @Args("sys_test_groupId", { type: () => Int }) sys_test_groupId: number,
    @Args("desc", { nullable: true }) desc?: string,
    @Args("order", { nullable: true, type: () => Int }) order?: number,
    @Args("status", { nullable: true }) status?: boolean,
  ) {
    return await this.service.createTest(name, base64, sys_test_groupId, desc, order, status)
  }

  @Mutation(() => SysTestEntity)
  @UseGuards(TestGuard([UPDATE_POWER]))
  async updateTest(
    @Args("id", { type: () => Int }) id: number,
    @Args("name") name: string,
    @Args("sys_test_groupId", { type: () => Int }) sys_test_groupId: number,
    @Args("desc", { nullable: true }) desc?: string,
    @Args("order", { nullable: true, type: () => Int }) order?: number,
    @Args("status", { nullable: true }) status?: boolean,
    @Args("base64", { nullable: true }) base64?: string,
  ) {
    const entity = await this.prisma.sys_test.update({
      where: {
        id
      },
      data: {
        name,
        desc,
        order,
        status,
        sys_test_groupId
      }
    })
    if (!entity) throw new ForbiddenError("404")
    if (base64) {
      const buffer = this.file.base64_to_buffer(base64)
      this.file.writeFile(this.service.getTestAvatarPath(entity), buffer);
    }
    return entity
  }

  @Mutation(() => SysTestEntity)
  @UseGuards(TestGuard([DELETE_POWER]))
  async deleteTest(
    @Args("id", { type: () => Int }) id: number,
  ) {
    const entity = await this.prisma.sys_test.delete({
      where: {
        id
      }
    })
    if (!entity) throw new ForbiddenError("404")
    return entity
  }

  //模拟测试章节
  @Query(() => [SysTestChapterEntity])
  @UseGuards(NoAuthGqlAuthGuard)
  async queryTestChapters(
    @Args("id", { type: () => Int }) id: number,
    @GqlCurrentUser() user: SysUserEntity,
  ) {
    const condition = user ? {
      where: {
        sys_userId: user.id,
        end_time: { gte: new Date() }
      },
      select: { id: true }
    } : false;
    const data: any = await this.prisma.sys_test_chapter.findMany({
      where: {
        sys_testId: id
      },
      include: {
        sys_user_power: condition
      }
    });
    data.map((chapter) => {
      chapter.is_lock = chapter.sys_user_power === undefined || chapter.sys_user_power.length == 0;
    });
    return data
  }
  @Query(() => [SysTestChapterEntity])
  queryTestChaptersByName(
    @Args("name", { type: () => String, nullable: true }) name?: string
  ) {
    return this.prisma.sys_test_chapter.findMany({
      where: {
        OR: [{
          name: {
            contains: name
          }
        }, {
          test: {
            name: {
              contains: name
            }
          }
        }]
      },
      include: {
        test: true
      },
      orderBy: {
        id: "desc"
      }
    })
  }

  @Query(() => SysTestChapterEntity)
  @UseGuards(NoAuthGqlAuthGuard)
  async queryTestChapterById(
    @Args("id", { type: () => Int }) id: number,
    @Args("papers", { nullable: true, type: () => Boolean }) papers: boolean = false,
    @GqlCurrentUser() user: SysUserEntity,
  ) {
    const condition = user ? {
      where: {
        sys_userId: user.id,
        end_time: { gte: new Date() }
      },
      select: { id: true }
    } : false;
    const data: any = await this.prisma.sys_test_chapter.findUnique({
      where: {
        id
      },
      include: {
        papers,
        sys_user_power: condition
      }
    });
    const resources = this.service.getChapterResourceList(data)
    data.is_lock = data.sys_user_power === undefined || data.sys_user_power.length == 0;
    return { ...data, resources };
  }

  @Mutation(() => SysTestChapterEntity)
  @UseGuards(TestGuard([CREATE_POWER]))
  async createTestChapter(
    @Args("sys_testId", { type: () => Int }) sys_testId: number,
    @Args("name") name: string,
    @Args("is_test", { type: () => Boolean, nullable: true }) is_test?: boolean,
    @Args("money", { type: () => Int, nullable: true }) money?: number,
    @Args("desc", { nullable: true }) desc?: string,
    @Args("order", { nullable: true, type: () => Int }) order?: number,
    @Args("status", { nullable: true }) status?: boolean,
    @Args("PPT", { nullable: true }) PPT?: string,
    @Args("PDF", { nullable: true }) PDF?: string,
    @Args("video", { nullable: true }) video?: string,
    @Args("one2one", { nullable: true }) one2one?: string,
    @Args("outline", { nullable: true }) outline?: string,
  ) {
    return this.service.createTestChapter(sys_testId, name,
      is_test, money, desc,
      order, status, PPT,
      PDF, video, one2one, outline);
  }

  @Mutation(() => SysTestChapterEntity)
  @UseGuards(TestGuard([UPDATE_POWER]))
  async updateTestChapter(
    @Args("id", { type: () => Int }) id: number,
    @Args("name") name: string,
    @Args("is_test", { type: () => Boolean, nullable: true }) is_test?: boolean,
    @Args("money", { type: () => Int, nullable: true }) money?: number,
    @Args("desc", { nullable: true }) desc?: string,
    @Args("order", { nullable: true, type: () => Int }) order?: number,
    @Args("status", { nullable: true }) status?: boolean,
    @Args("PPT", { nullable: true }) PPT?: string,
    @Args("PDF", { nullable: true }) PDF?: string,
    @Args("video", { nullable: true }) video?: string,
    @Args("one2one", { nullable: true }) one2one?: string,
    @Args("outline", { nullable: true }) outline?: string,
  ) {
    const entity = await this.prisma.sys_test_chapter.update({
      where: {
        id
      },
      data: {
        name,
        desc,
        order,
        status,
        PPT,
        PDF,
        video,
        one2one,
        outline,
        money,
        is_test
      }
    })
    if (!entity) throw new ForbiddenError("404")
    return entity
  }

  @Mutation(() => SysTestChapterEntity)
  @UseGuards(TestGuard([DELETE_POWER]))
  async deleteTestChapter(
    @Args("id", { type: () => Int }) id: number,
  ) {
    const entity = await this.prisma.sys_test_chapter.delete({
      where: {
        id
      }
    })
    if (!entity) throw new ForbiddenError("404")
    return entity
  }

  @Query(() => [SysTestPaperEntity])
  @UseGuards(TestGuard([VIEW_POWER]))
  queryTestPapers(
    @Args("id", { type: () => Int }) id: number
  ) {
    return this.prisma.sys_test_paper.findMany({
      where: {
        sys_test_chapterId: id
      }
    })
  }

  @Query(() => SysTestPaperEntity)
  @UseGuards(GqlAuthGuard)
  async queryTestPaperById(
    @Args("id", { type: () => Int }) id: number,
    @Args("questions", { nullable: true, type: () => Boolean }) questions: boolean = false,
    @GqlCurrentUser() user: SysUserEntity
  ) {
    if (!await this.questionService.canReadPaper(id, user)) throw new Error("你没有权限查看这个章节");
    return await this.prisma.sys_test_paper.findUnique({
      where: {
        id
      },
      include: {
        questions
      }
    })
  }

  @Mutation(() => SysTestPaperEntity)
  @UseGuards(TestGuard([CREATE_POWER]))
  async createTestPaper(
    @Args("name") name: string,
    @Args("sys_test_chapterId", { type: () => Int }) sys_test_chapterId: number,
    @Args("desc", { nullable: true }) desc?: string,
    @Args("order", { nullable: true, type: () => Int }) order?: number,
    @Args("status", { nullable: true }) status?: boolean,
    @Args("is_free", { nullable: true }) is_free?: boolean,
    @Args("time", { nullable: true, type: () => Int }) time?: number,
  ) {
    return await this.service.createTestPaper(name, sys_test_chapterId,
      desc, order, status, is_free, time);
  }

  @Mutation(() => SysTestPaperEntity)
  @UseGuards(TestGuard([UPDATE_POWER]))
  async updateTestPaper(
    @Args("id", { type: () => Int }) id: number,
    @Args("name") name: string,
    @Args("desc", { nullable: true }) desc?: string,
    @Args("order", { nullable: true, type: () => Int }) order?: number,
    @Args("status", { nullable: true }) status?: boolean,
    @Args("is_free", { nullable: true }) is_free?: boolean,
    @Args("time", { nullable: true, type: () => Int }) time?: number,
  ) {
    const entity = await this.prisma.sys_test_paper.update({
      where: {
        id
      },
      data: {
        name,
        desc,
        order,
        status,
        is_free,
        time,
      }
    })
    if (!entity) throw new ForbiddenError("404")
    return entity
  }

  @Mutation(() => SysTestPaperEntity)
  @UseGuards(TestGuard([DELETE_POWER]))
  async deleteTestPaper(
    @Args("id", { type: () => Int }) id: number,
  ) {
    const entity = await this.prisma.sys_test_paper.delete({
      where: {
        id
      }
    })
    if (!entity) throw new ForbiddenError("404")
    return entity
  }

  @Mutation(() => [Int])
  @UseGuards(TestGuard([CREATE_POWER]))
  async createTestByJson(
    @Args("sys_test_groupId", { type: () => Int }) sys_test_groupId: number,
    @Args("json", { nullable: true }) json?: string,
    @Args("path", { nullable: true }) path?: string,
  ) {
    if (!json && !path) throw new Error("你倒是传个东西来也行啊")
    return this.service.createTestByJson(json, path, sys_test_groupId);
  }
}